package cz.muni.fi.pa165.rentalofconstructionmachinery.restclient;

import cz.muni.fi.pa165.rentalofconstructionmachinery.CustomerType;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.security.crypto.codec.Base64;

/**
 * Sample rest client - main entry point for the app.
 * 
 * @author Zuzana Krejcova
 */
public class App {
    
    public static String WEBAPP_LOCATION = "http://localhost:8080/pa165/rest/";
    
    private static final Logger infoLogger = LoggerFactory.getLogger("info");
    private static final Logger errorLogger = LoggerFactory.getLogger("error");
    
    private static final String ENTITY = "entity";
    private static final String ACTION = "action";
    private static final String ID = "id";
    private static final String TYPE = "type";
    private static final String CUSTOMER_NAME = "name";
    private static final String CUSTOMER_USERNAME = "username";
    private static final String CUSTOMER_PASSWORD = "password";
    private static final String LICENSE_PLATE = "licensePlate";
    private static final String CUSTOMER = "customer";
    private static final String MACHINE = "machine";
    private static final String ENTITY_WARNING = "Please, specify a supported entity (customer, machine).";
   
    private static final String REST_USERNAME = "rest";
    private static final String REST_PASSWORD = "rest";
    
    public static int main(String[] args) {
        
        infoLogger.info("\n\nREST Sample Client\n\n");
                
        HttpHeaders httpHeaders = new HttpHeaders();
        String auth = REST_USERNAME + ":" + REST_PASSWORD;
        byte[] encodedAuthorisation = Base64.encode(auth.getBytes());
        httpHeaders.add("Authorization", "Basic " + new String(encodedAuthorisation));
        
        CustomerRestController.setHttpHeaders(httpHeaders);
        MachineRestController.setHttpHeaders(httpHeaders);
        
        try {
            switch (System.getProperty(ACTION, "")) {
                case "list" :
                    listEntities();
                    break;
                case "details" :
                    getDetails();
                    break;
                case "create" :
                    createEntity();
                    break;
                case "edit" :
                    editEntity();
                    break;
                case "delete" :
                    deleteEntity();
                    break;
                default : infoLogger.info("Please, see the usage guide for this client in the README file.");
            }
        } catch (Exception e) {
            errorLogger.error("Houston, we have a problem.", e);
            infoLogger.info("\n\n");
            infoLogger.info("Ooops.");
            return 1;
        }
        
        infoLogger.info("\n\n");
        infoLogger.info("The operation was successful.");
        return 0;
    }
    
    private static void listEntities() throws URISyntaxException {
        switch (getPropertyOrDie(ENTITY)) {
            case CUSTOMER :
                infoLogger.info("Listing customers.");
                infoLogger.info(CustomerRestController.listCustomers().toString());
                break;
            case MACHINE :
                infoLogger.info("Listing machines.");
                infoLogger.info(MachineRestController.listMachines().toString());
                break;
            default : errorLogger.error(ENTITY_WARNING);
        }
    }
    
    private static void createEntity() {
        switch (getPropertyOrDie(ENTITY)) {
            case CUSTOMER :
                infoLogger.info("Creating a new customer.");
                CustomerRestController.newCustomer(getPropertyOrDie(CUSTOMER_NAME), getCustomerType(), getPropertyOrDie(CUSTOMER_USERNAME), getPropertyOrDie(CUSTOMER_PASSWORD));
                break;
            case MACHINE :
                infoLogger.info("Creating a new machine.");
                MachineRestController.newMachine(getPropertyOrDie(LICENSE_PLATE), getPropertyOrDie(TYPE));
                break;
            default : errorLogger.error(ENTITY_WARNING);
        }
    }
    
    private static void getDetails() throws URISyntaxException {
        switch (getPropertyOrDie(ENTITY)) {
            case CUSTOMER :
                infoLogger.info("Getting details for a customer.");
                infoLogger.info(CustomerRestController.customerDetails(getID()).toString());
                break;
            case MACHINE :
                infoLogger.info("Getting details for a machine.");
                infoLogger.info(MachineRestController.machineDetails(getID()).toString());
                break;
            default : errorLogger.error(ENTITY_WARNING);
        }
    }
    
    private static void editEntity() {
        switch (getPropertyOrDie(ENTITY)) {
            case CUSTOMER :
                infoLogger.info("Editing a customer.");
                CustomerRestController.editCustomer(getID(), getPropertyOrDie(CUSTOMER_NAME), getCustomerType(), getPropertyOrDie(CUSTOMER_USERNAME), getPropertyOrDie(CUSTOMER_PASSWORD));
                break;
            case MACHINE :
                infoLogger.info("Editing a machine.");
                MachineRestController.editMachine(getID(), getPropertyOrDie(LICENSE_PLATE), getPropertyOrDie(TYPE));
                break;
            default : errorLogger.error(ENTITY_WARNING);
        }
    }
    
    private static void deleteEntity() throws URISyntaxException {
        switch (getPropertyOrDie(ENTITY)) {
            case CUSTOMER :
                infoLogger.info("Deleting a customer.");
                CustomerRestController.deleteCustomer(getID());
                break;
            case MACHINE :
                infoLogger.info("Deleting a machine.");
                MachineRestController.deleteMachine(getID());
                break;
            default : errorLogger.error(ENTITY_WARNING);
        }
    }
    
    private static CustomerType getCustomerType() {
        String type = getPropertyOrDie(TYPE);
        switch (type) {
            case "legal" :
                return CustomerType.LEGAL;
            case "physical" :
                return CustomerType.PHYSICAL;
            default : throw new IllegalArgumentException(
                    "Property 'type' must be one of [legal, physical] for a customer entity.");
        }
    }
    
    private static Long getID() {
        String idProp = getPropertyOrDie(ID);
        Long id = null;
        try {
            id = Long.parseLong(idProp);
        } catch (NumberFormatException nfe) {
            throw new IllegalArgumentException("Property 'id' must be a number.", nfe);
        }
        return id;
    }
    
    private static String getPropertyOrDie(String propertyName) {
        String value = System.getProperty(propertyName, "");
        while ((value == null) || value.isEmpty() || value.equals("true")) {
            System.out.print("The client needs '"+propertyName+"' argument. Please, type the value and hit Enter key: ");
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            try {
                value = br.readLine();
            } catch (IOException ex) {
                throw new IllegalArgumentException("Couldn't get the required argument '"+propertyName+"'.", ex);
            }
        }
        return value;
    }
}
